package com.icim.core.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.icim.core.pojo.FtpConfigure;
import com.icim.core.service.IFtpService;
import com.icim.exception.ICIMException;

public class FtpServiceImpl implements IFtpService {

    private Logger logger = LoggerFactory.getLogger(FtpServiceImpl.class);

    private final String ENCODING_TYPE_GBK = "GBK";
    private final String OUTPUT_STREAM_TYPE = "ISO-8859-1";
    private final String SERVER_LANGUAGE_CODE_CHINESE = "zh";

    private FtpConfigure ftpConfigure;
    private FTPClient ftpClient;

    public FtpConfigure getFtpConfigure() {
        return ftpConfigure;
    }

    public void setFtpConfigure(FtpConfigure ftpConfigure) {
        this.ftpConfigure = ftpConfigure;
    }

    @Override
    public boolean connect() throws Exception {
        ftpClient = new FTPClient();
        ftpClient.connect(ftpConfigure.getHost(), ftpConfigure.getPort());
        ftpClient.login(ftpConfigure.getUsername(), ftpConfigure.getPassword());
        // 检测连接是否成功
        for (int i = 0; i < 3; i++) {
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                logger.warn("connectin refused , reconnect ...");
                reconnect();
            } else {
                break;
            }
        }
        ftpClient.changeWorkingDirectory(ftpConfigure.getSourcePath());
        logger.info("connect to ftp  ....." );
        return true;
    }

    @Override
    public boolean reconnect() throws Exception {
        ftpClient = new FTPClient();
        ftpClient.connect(ftpConfigure.getHost(), ftpConfigure.getPort());
        ftpClient.login(ftpConfigure.getUsername(), ftpConfigure.getPassword());
        // 检测连接是否成功
        int reply = ftpClient.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftpClient.disconnect();
            throw new ICIMException("FTP server refused connection.");
        }
        ftpClient.changeWorkingDirectory(ftpConfigure.getSourcePath());
        return true;
    }

    public void disconnectFtp() throws IOException {
        if (ftpClient != null) {
            ftpClient.disconnect();
        }
    }

    public List<String> listFiles(String fileExt) throws IOException {
        List<String> fileNameList = new ArrayList<String>();
        FTPFile[] ftpFiles = ftpClient.listFiles();

        for (int i = 0; i < ftpFiles.length; i++) {
            FTPFile ftpFile = ftpFiles[i];

            logger.info("find file :" + ftpFile.getName());
            if (!StringUtils.isEmpty(fileExt)) {
                if (!ftpFile.getName().toUpperCase().endsWith(fileExt.toUpperCase())) {
                    logger.warn("not match fileExt:" + ftpFile.getName());
                    continue;
                }
            }

            fileNameList.add(ftpFile.getName());
        }
        return fileNameList;
    }

    /**
     * 
     * @param fileName
     * @throws UnsupportedEncodingException
     * @throws IOException
     */
    public void downLoadFile(String fileName) throws UnsupportedEncodingException, IOException {
        ftpClient.setControlEncoding(ENCODING_TYPE_GBK);
        FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
        conf.setServerLanguageCode(SERVER_LANGUAGE_CODE_CHINESE);

        ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        File localFile = new File(ftpConfigure.getLocalTemporaryPath() + "/" + fileName);

        OutputStream outputStream = new FileOutputStream(localFile);
        ftpClient.retrieveFile(new String(fileName.getBytes(ENCODING_TYPE_GBK), OUTPUT_STREAM_TYPE), outputStream);
        outputStream.close();

    }

    public void uploadFile(File file) throws IOException {
        String ftpExportPath = ftpConfigure.getFtpExportPath();
        uploadFile(file, ftpExportPath);
    }

    public void uploadFile(File file, String uploadPath) throws IOException {
        logger.info(uploadPath);
        ftpClient.changeWorkingDirectory(uploadPath);

        File file2 = new File(file.getPath());
        InputStream input = new FileInputStream(file2);

        // 设置缓冲
        ftpClient.setBufferSize(1024);

        // 设置文件类型(二进制类型)
        if (ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE)) {
            ftpClient.storeFile(file.getName(), input);
        }
        input.close();
    }

    /**
     * 
     * @param fileName
     * @param isOK
     * @throws IOException
     */
    public void removeFiles(String fileName, boolean isOK) throws IOException {
        String newFilePath = getDestinFilePath(fileName, isOK);
        String originalFilePath = ftpConfigure.getSourcePath() + "/" + fileName;

        ftpClient.changeWorkingDirectory(ftpConfigure.getSourcePath());
        ftpClient.rename(originalFilePath, newFilePath);
        logger.info("move from {} to {}", originalFilePath, newFilePath);
    }

    private String getDestinFilePath(String fileName, boolean isOK) {
        String okPath = ftpConfigure.getFtpOkPath() + "/" + fileName;
        String ngPath = ftpConfigure.getFtpNgPath() + "/" + fileName;
        return isOK ? okPath : ngPath;
    }

}
